package com.zb.zeus.common.redis.service;

import java.time.Duration;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.TimeoutUtils;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

/**
 * redis基础封装
 *
 * @author liangfan
 * @date 2021/07/13 10:08
 **/
//@SuppressWarnings(value = { "unchecked", "rawtypes" })
public abstract class BaseRedisComponent implements IRedisComponent {

    private IRoundExpireTime roundExpireTime;
    private RedisTemplate redisTemplate;

    public BaseRedisComponent(IRoundExpireTime roundExpireTime, RedisTemplate redisTemplate) {
        this.roundExpireTime = roundExpireTime;
        this.redisTemplate = redisTemplate;
    }

    /**
     * 组装key
     *
     * @param key
     * @return java.lang.String
     * @author liangfan
     * @date 2021/7/13 10:54
     */
    private String genKey(String key) {
        return getKeyPre() + key;
    }

    /**
     * 生成失效时间
     *
     * @param expireTime
     * @return long
     * @author liangfan
     * @date 2021/7/13 10:58
     */
    private long genExpireTime(long expireTime) {
        return roundExpireTime.getExpireTimeByRound(expireTime);
    }



    /***********************************************************************************************/



    /**
     * 设置key失效时间
     *
     * @param key
     * @param timeout
     * @param unit
     * @return
     */
    public Boolean expire(String key, long timeout, TimeUnit unit) {
        key = genKey(key);
        timeout = genExpireTime(timeout);
        return redisTemplate.expire(key, timeout, unit);
    }

    /**
     * 设置失效时间
     *
     * @param key
     * @param timeout
     * @return
     */
    public Boolean expire(String key, Duration timeout) {

        Assert.notNull(timeout, "Timeout must not be null");
        boolean hasMs = TimeoutUtils.hasMillis(timeout);

        long expireTime = 0;
        if (hasMs) {
            expireTime = timeout.toMillis();
            return expire(key, expireTime, TimeUnit.MILLISECONDS);
        } else {
            expireTime = timeout.getSeconds();
            return expire(key, expireTime, TimeUnit.SECONDS);
        }
    }

    /**
     * 批量删除keys
     *
     * @param keys
     * @return
     */
    public Long delete(Collection<String> keys) {
        if (CollectionUtils.isEmpty(keys)) {
            return 0L;
        }
        Collection<String> ks = new HashSet<>();
        keys.forEach(key -> ks.add(genKey(key)));

        return redisTemplate.delete(ks);
    }

    /**
     * 删除key
     *
     * @param key
     * @return
     */
    public Boolean delete(String key) {
        key = genKey(key);
        return redisTemplate.delete(key);
    }

    /**
     * 是否存在key
     *
     * @param key
     * @return
     */
    public Boolean hasKey(String key) {
        key = genKey(key);
        return redisTemplate.hasKey(key);
    }

    /**
     * 模糊查找key
     *
     * @param pattern
     * @return
     */
    public Set<String> keys(String pattern) {
        pattern = genKey(pattern);
        return redisTemplate.keys(pattern);
    }

    /***********************************************************************************************/
//    private void t() {
//        redisTemplate.opsForValue().setIfAbsent()
//    }

    /**
     * 批量获取
      * @param keys
     * @param <T>
     * @return
     */
    public<T> List<T> multiGet(Collection<String> keys){
        Collection<String> ks = new HashSet<>();
        keys.forEach(key -> ks.add(genKey(key)));
        return redisTemplate.opsForValue().multiGet(ks);
    }

    /**
     * 获取
     *
     * @param key
     * @return
     */
    public <T> T get(String key) {
        key = genKey(key);
        return (T) redisTemplate.opsForValue().get(key);
    }

    /**
     * @param key
     * @param value
     */
    public <T> void set(String key, T value) {
        key = genKey(key);
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * @param key
     * @param value
     * @param timeout
     * @param unit
     */
    public <T> void set(String key, T value, long timeout, TimeUnit unit) {
        key = genKey(key);
        timeout = genExpireTime(timeout);
        redisTemplate.opsForValue().set(key, value, timeout, unit);
    }

    /**
     * 不存在时，设置
     * @param key
     * @param value
     * @param <T>
     * @return
     */
    public <T> Boolean setIfAbsent(String key, T value){
        key = genKey(key);
        return redisTemplate.opsForValue().setIfAbsent(key,value);
    }

    /**
     * 不存在时，设置
     * @param key
     * @param value
     * @param timeout
     * @param unit
     * @param <T>
     * @return
     */
    public <T> Boolean setIfAbsent(String key, T value, long timeout,TimeUnit unit){
        key = genKey(key);
        timeout = genExpireTime(timeout);
        return redisTemplate.opsForValue().setIfAbsent(key,value,timeout,unit);
    }

    /***********************************************************************************************/
    /**
     * 获取hash
     *
     * @param key
     * @return
     */
    public <K, V> Map<K, V> hEntries(String key) {
        key = genKey(key);
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * 自增某个值
     *
     * @param key
     * @param hKey
     * @param increment
     * @return
     */
    public Long hIncrement(String key, String hKey, long increment) {
        key = genKey(key);
        return redisTemplate.opsForHash().increment(key, hKey, increment);
    }

    /**
     * @param key
     * @param m
     */
    public <K, V> void hPutAll(String key, Map<K, V> m) {
        key = genKey(key);
        redisTemplate.opsForHash().putAll(key, m);
    }

    /***********************************************************************************************/
}
